package com.cmy.scheduleLite.config;

import com.cmy.scheduleLite.bean.ScheduleSetting;
import com.cmy.scheduleLite.bean.ScheduledTask;
import com.cmy.scheduleLite.bean.SchedulingRunnable;
import com.cmy.scheduleLite.service.ScheduleSettingLoader;
import com.cmy.scheduleLite.utils.CronUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author : Cmy
 * @date : 2025-04-09 9:09
 */
@Slf4j
@Component
public class CronTaskRegister implements InitializingBean, DisposableBean {

    @Resource
    private ScheduleSettingLoader scheduleSettingLoader;

    /**
     * key runnable
     * value ScheduledTask
     * 缓存所有定时任务
     */
    private final Map<Runnable, ScheduledTask> scheduledTasks = new ConcurrentHashMap<>(16);

    private TaskScheduler taskScheduler;

    public TaskScheduler getScheduler() {
        return this.taskScheduler;
    }

    /**
     * 注册
     * @param scheduleSetting
     */
    public void register(ScheduleSetting scheduleSetting) {
        //Long jobId = scheduleSetting.getJobId();
        String beanName = scheduleSetting.getBeanName();
        String methodName = scheduleSetting.getMethodName();
        String methodParams = scheduleSetting.getMethodParams();
        String cronExpression = scheduleSetting.getCronExpression();
        //判断表达式是否在合理时间内（下一次执行时间<10年)
        if (!CronUtils.isTimeSpanTooLongCron(cronExpression)) {
            Integer jobStatus = scheduleSetting.getJobStatus();
            if (Objects.equals(jobStatus, 1)) {
                SchedulingRunnable runnable = new SchedulingRunnable(beanName, methodName, methodParams);
                addCronTask(runnable, cronExpression);
                return;
            }
            log.info("\n" +
                    "注册任务:\n{}", scheduleSetting);
        }else {
            log.warn("由于cron下一次执行时间过长,该定时任务不会生效\n" +
                    "{} ",scheduleSetting);
        }
    }

    /**
     * 删除
     * @param scheduleSetting
     */
    public void unRegister(ScheduleSetting scheduleSetting) {
        SchedulingRunnable task = new SchedulingRunnable(scheduleSetting.getBeanName(), scheduleSetting.getMethodName(), scheduleSetting.getMethodParams());
        removeCronTask(task);
    }

    private void addCronTask(Runnable task, String cronExpression) {
        addCronTask(new CronTask(task, cronExpression));
    }

    private void addCronTask(CronTask cronTask) {
        if (cronTask != null) {
            Runnable task = cronTask.getRunnable();
            if (this.scheduledTasks.containsKey(task)) {
                removeCronTask(task);
            }

            this.scheduledTasks.put(task, scheduleCronTask(cronTask));
        }
    }

    private void removeCronTask(Runnable task) {
        ScheduledTask scheduledTask = this.scheduledTasks.remove(task);
        if (scheduledTask != null)
            scheduledTask.cancel();
    }

    private ScheduledTask scheduleCronTask(CronTask cronTask) {
        ScheduledTask scheduledTask = new ScheduledTask(cronTask);
        scheduledTask.future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
        return scheduledTask;
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        // 手动创建并配置ThreadPoolTaskScheduler
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        // 定时任务执行线程池核心线程数
        scheduler.setPoolSize(Runtime.getRuntime().availableProcessors());
        scheduler.setRemoveOnCancelPolicy(true);
        scheduler.setThreadNamePrefix("scheduler-thread-pool-");
        scheduler.initialize();
        this.taskScheduler = scheduler;

        //加载配置
        List<ScheduleSetting> scheduleSettingList = scheduleSettingLoader.load();
        for (ScheduleSetting scheduleSetting : scheduleSettingList) {
            String cronExpression = scheduleSetting.getCronExpression();
            if (!CronUtils.isTimeSpanTooLongCron(cronExpression)&&scheduleSetting.getJobStatus()==1) {
                register(scheduleSetting);
            }else {
                log.info("filter scheduled task : {}", scheduleSetting.getJobId());
            }
        }

    }


    @Override
    public void destroy() throws Exception {
        //清除 任务
        log.info("清除任务");
        for (ScheduledTask task : this.scheduledTasks.values()) {
            task.cancel();
        }
        this.scheduledTasks.clear();
    }


}

    